/* -*- P4_16 -*- */
#include <core.p4>
#include <v1model.p4>

// 定义网络相关常量（IP、协议类型、端口、MAC等）
const bit<32> TARGET_H4_IP_ADDR = 0x0a000104;        // 目标主机H4的IP地址（10.0.1.4）
const bit<16> ETH_PROTOCOL_IPV4 = 0x800;             // 以太网IPv4协议类型标识
const bit<8>  IP_PROTOCOL_TCP = 6;                   // IP层TCP协议标识
const bit<8>  IP_PROTOCOL_UDP = 17;                  // IP层UDP协议标识
const bit<16> UDP_BLOCKED_DEST_PORT = 80;            // 需阻断的UDP目标端口
const bit<48> SWITCH_DEFAULT_MAC = 0x080000000100;   // 交换机默认源MAC地址

// 以太网头部定义（包含MAC地址和以太网协议类型）
header ethernet_header {
    bit<48> dest_mac_addr;  // 目标MAC地址
    bit<48> src_mac_addr;   // 源MAC地址
    bit<16> eth_proto;      // 以太网协议类型
}

// IPv4头部定义（包含IP层核心字段）
header ipv4_header {
    bit<4>  ip_version;     // IP协议版本（IPv4为4）
    bit<4>  ip_header_len;  // IP头部长度（单位：32bit）
    bit<8>  diff_serv_field;// 区分服务字段
    bit<16> ip_total_len;   // IP数据包总长度
    bit<16> ip_id;          // IP数据包标识
    bit<3>  ip_flags;       // IP分片标志
    bit<13> frag_offset;    // 分片偏移量
    bit<8>  ip_ttl;         // 生存时间（TTL）
    bit<8>  ip_proto;       // 上层协议（TCP/UDP等）
    bit<16> ip_checksum;    // IP头部校验和
    bit<32> src_ip_addr;    // 源IP地址
    bit<32> dest_ip_addr;   // 目标IP地址
}

// UDP头部定义（包含UDP端口和长度等字段）
header udp_header {
    bit<16> udp_src_port;   // UDP源端口
    bit<16> udp_dest_port;  // UDP目标端口
    bit<16> udp_total_len;  // UDP数据包总长度
    bit<16> udp_checksum;   // UDP校验和
}

// TCP头部定义（包含TCP端口字段，此处为简化定义）
header tcp_header {
    bit<16> tcp_src_port;   // TCP源端口
    bit<16> tcp_dest_port;  // TCP目标端口
}

// 元数据结构（用于存储自定义转发逻辑标记）
struct metadata {
    bit<1> udp_filter_flag; // 标记UDP是否被过滤丢弃
}

// 头部集合（聚合所有协议头部）
struct headers {
    ethernet_header eth_hdr;
    ipv4_header     ipv4_hdr;
    udp_header      udp_hdr;
    tcp_header      tcp_hdr;
}

// 数据包解析器（负责从原始数据包中提取各层头部）
parser AclPacketParser(packet_in packet,
                       out headers hdr,
                       inout metadata meta,
                       inout standard_metadata_t standard_metadata) {
    state start {
        transition parse_ethernet_hdr;
    }
    state parse_ethernet_hdr {
        packet.extract(hdr.eth_hdr); // 提取以太网头部
        transition select(hdr.eth_hdr.eth_proto) { // 根据以太网协议类型选择后续解析逻辑
            ETH_PROTOCOL_IPV4: parse_ipv4_hdr;
            default: accept;
        }
    }
    state parse_ipv4_hdr {
        packet.extract(hdr.ipv4_hdr); // 提取IPv4头部
        transition select(hdr.ipv4_hdr.ip_proto) { // 根据IP协议类型选择后续解析逻辑
            IP_PROTOCOL_UDP: parse_udp_hdr;
            IP_PROTOCOL_TCP: parse_tcp_hdr;
            default: accept;
        }
    }
    state parse_udp_hdr {
        packet.extract(hdr.udp_hdr); // 提取UDP头部
        transition accept;
    }
    state parse_tcp_hdr {
        packet.extract(hdr.tcp_hdr); // 提取TCP头部
        transition accept;
    }
}

// 校验和验证控制块（此处无实际逻辑，仅为P4架构兼容）
control AclChecksumVerifier(inout headers hdr, inout metadata meta) {
    apply {}
}

// 入端口处理控制块（实现转发、过滤等核心逻辑）
control AclIngressProcessor(inout headers hdr,
                            inout metadata meta,
                            inout standard_metadata_t standard_metadata) {
    // 丢弃UDP数据包的动作
    action filter_udp_packet() {
        mark_to_drop(standard_metadata); // 标记数据包为丢弃
        meta.udp_filter_flag = 1;       // 设置UDP过滤标记
    }
    // 通用丢弃数据包的动作
    action drop_packet() {
        mark_to_drop(standard_metadata);
    }
    // 转发数据包的动作（设置下一跳MAC和出端口）
    action set_next_hop(bit<48> dest_mac, bit<9> egress_port) {
        hdr.eth_hdr.dest_mac_addr = dest_mac; // 重写目标MAC地址
        standard_metadata.egress_spec = egress_port; // 设置出端口
        hdr.ipv4_hdr.ip_ttl = hdr.ipv4_hdr.ip_ttl - 1; // TTL减1
    }

    // UDP 80端口过滤表（精确匹配UDP目标端口）
    table udp_port80_filter_table {
        key = { hdr.udp_hdr.udp_dest_port: exact; }
        actions = { filter_udp_packet; NoAction; }
        size = 1024;
        default_action = NoAction();
    }
    // IPv4转发表（最长前缀匹配目标IP地址）
    table ipv4_forwarding_table {
        key = { hdr.ipv4_hdr.dest_ip_addr: lpm; }
        actions = { set_next_hop; drop_packet; }
        size = 1024;
        default_action = drop_packet();
    }

    apply {
        meta.udp_filter_flag = 0; // 初始化UDP过滤标记
        if (hdr.ipv4_hdr.isValid() && hdr.ipv4_hdr.ip_ttl > 0) { // 仅处理有效的IPv4数据包且TTL>0
            // 阻断对H4主机的访问
            if (hdr.ipv4_hdr.dest_ip_addr == TARGET_H4_IP_ADDR) {
                drop_packet();
                return;
            }
            // 过滤UDP 80端口的数据包
            if (hdr.ipv4_hdr.ip_proto == IP_PROTOCOL_UDP && hdr.udp_hdr.isValid()) {
                udp_port80_filter_table.apply();
                if (meta.udp_filter_flag == 1) {
                    return;
                }
            }
            // 执行IPv4转发
            ipv4_forwarding_table.apply();
        }
    }
}

// 出端口处理控制块（实现MAC地址重写）
control AclEgressProcessor(inout headers hdr,
                           inout metadata meta,
                           inout standard_metadata_t standard_metadata) {
    // 重写源MAC地址的动作
    action rewrite_source_mac(bit<48> source_mac) {
        hdr.eth_hdr.src_mac_addr = source_mac; // 重写源MAC地址
    }
    // MAC重写表（根据出端口匹配并执行MAC重写）
    table mac_rewrite_table {
        key = { standard_metadata.egress_port: exact; }
        actions = { rewrite_source_mac; }
        size = 256;
        default_action = rewrite_source_mac(SWITCH_DEFAULT_MAC); // 默认重写为交换机MAC
    }
    apply {
        mac_rewrite_table.apply(); // 应用MAC重写规则
    }
}

// 校验和计算控制块（更新IPv4头部校验和）
control AclChecksumCalculator(inout headers hdr, inout metadata meta) {
    apply {
        update_checksum(
            hdr.ipv4_hdr.isValid(), // 仅对有效的IPv4头部计算校验和
            { hdr.ipv4_hdr.ip_version,
              hdr.ipv4_hdr.ip_header_len,
              hdr.ipv4_hdr.diff_serv_field,
              hdr.ipv4_hdr.ip_total_len,
              hdr.ipv4_hdr.ip_id,
              hdr.ipv4_hdr.ip_flags,
              hdr.ipv4_hdr.frag_offset,
              hdr.ipv4_hdr.ip_ttl,
              hdr.ipv4_hdr.ip_proto,
              hdr.ipv4_hdr.src_ip_addr,
              hdr.ipv4_hdr.dest_ip_addr
            },
            hdr.ipv4_hdr.ip_checksum, // 待更新的校验和字段
            HashAlgorithm.csum16      // 校验和算法（16位累加和）
        );
    }
}

// 数据包解解析器（将各层头部组装回原始数据包）
control AclPacketDeparser(packet_out packet, in headers hdr) {
    apply {
        packet.emit(hdr.eth_hdr);  // 输出以太网头部
        packet.emit(hdr.ipv4_hdr); // 输出IPv4头部
        packet.emit(hdr.udp_hdr);  // 输出UDP头部
        packet.emit(hdr.tcp_hdr);  // 输出TCP头部
    }
}

// 交换机实例化（关联所有控制块）
V1Switch(
    AclPacketParser(),         // 数据包解析器
    AclChecksumVerifier(),     // 校验和验证
    AclIngressProcessor(),     // 入端口处理
    AclEgressProcessor(),      // 出端口处理
    AclChecksumCalculator(),   // 校验和计算
    AclPacketDeparser()        // 数据包解解析器
) main;